#!/usr/bin/env ruby
	require "socket"
	require "date"
include Socket::Constants

def conf
	tab = []
	fic = File.open("./VolcanoConfig.yml")
	fic.each_line{|ligne|
		word = ligne.split(" " )
		tab << word[2]
	}
	$bind = tab[0].to_i
	$listen = tab[1].to_i
	$path = tab[2]
	$binary = tab[3].to_i
	$ascii = tab[4].to_i
	$minport = tab[5].to_i
	$maxport = tab[6].to_i
	$pathlog = tab[7]
	0
end

conf

def	log(args)
	myFile = File.open($pathlog, "a+")
	str = args + "\n"
	myFile.write(str)
	myFile.close
end

# Volcano FTP contants
BINARY_MODE = $binary
ASCII_MODE = $ascii
MIN_PORT = $minport
MAX_PORT = $maxport

# Volcano FTP class
class VolcanoFtp

  def initialize(port)
    # Prepare instance 
    @socket = TCPServer.new("", port)
    @socket.listen($bind)

	@path_ftp = $path
    @path_user = $path
    @transfert_type = BINARY_MODE
    @tsocket = nil
    puts "Server ready to listen for clients on port #{port}"

  end

  def ftp_syst(args)
    @cs.write "215 UNIX Type: L8\r\n"
    0
  end

  def ftp_noop(args)
    @cs.write "200 Don't worry my lovely client, I'm here ;)"
    0

  end

  def ftp_502(*args)
    puts "Command not found"
    @cs.write "502 Command not implemented\r\n"
    0
  end    
  
  def ftp_pwd(args)
	path = @path_user.gsub(@path_ftp,"")
	if (path.nil? || path == "")
	 path.insert(0, '/')
	end
    @cs.write "257 \"#{path}\"\r\n"
	0
  end

  def ftp_type(args)
    @cs.write "200 Switching to Binary mode\r\n"    
  end

  def ftp_retr(args)
	if (File.exist?(args))
		file = open("#{args}", "r")
		fileContent = file.read
		@t_socket.puts(fileContent)
		@t_socket.close
		@cs.write "125 canal de donnees deja ouvert, debut de tranfert\r\n"
		@cs.write "150 \r\n"
	else
	@cs.write "550 Failed to open file.\r\n"
	end
    0
  end
  
  def ftp_stor(args)
	puts "stor 0"
    fileContent = @t_socket.read(args)
    puts "stor 1"
    f = File.new("#{args}", "w")
    puts "stor 2"
    f.write("#{fileContent}")
    puts "stor 3"
    f.close
    @t_socket.close
    @cs.write "125 canal de donnees deja ouvert, debut de tranfert\r\n"

    @cs.write "150 \r\n"
    0
  end

  def ftp_list(args)
    #test = `ls -l .`
    ls = IO.read("|-") or exec("ls -l")
    #ls = ls.getbyte(0)
	#@cs.puts "#{ls}"
    @t_socket.puts "#{ls}\r\n"
    
    @t_socket.close
    @cs.write "125 canal de donnees deja ouvert, debut de tranfert\r\n"

    @cs.write "150 \r\n"
    0
  end

  def ftp_port(args)
    port2 = "#{args.split(',')[4].to_i*256 + args.split(',')[5].to_i}"
    @t_socket = TCPSocket.open("", port2)
	@cs.write "200 PORT command successful. Consider using PASV. \r\n"
    0
  end

  def ftp_pasv(args)
    @cs.write "227 Passage en mode passif\r\n"
    0
  end

  def ftp_cwd(args)
	puts "200 test0\r\n"
	if (args == "/")
		path = @path_ftp.to_s
	else
		path = @path_user.to_s+"/"+args
	end
	if Dir.exist?(path)
		@path_user = path
		Dir.chdir(path)
		@cs.write "200 directory changed to #{args}\r\n"
	else
		@cs.write "550 Failed to change directory.\r\n"
	end
    0
  end

  def ftp_quit(args)
    @cs.write "221 Thank you for using Volcano FTP\r\n"
	-1
  end

  def ftp_user(args)

    @cs.write "331 Guest login ok\r\n"
    0
  end

  def ftp_pass(args)
     @cs.write "230 Guest login ok, access restrictions apply.\r\n"
    0
  end 

  def method_missing(m, args)
    ftp_502()
    puts "There's no method called #{m} here -- please try again"
  end

  def run
    while (42)
      @cs,  = @socket.accept
      peeraddr = @cs.peeraddr.dup
      Kernel.fork do

        puts "[#{Process.pid}] Instanciating connection from #{@cs.peeraddr[2]}:#{@cs.peeraddr[1]}"
        date = DateTime.now
        str = "[#{Process.pid}] " << date.to_s << " connection in from #{@cs.peeraddr[2]}:#{@cs.peeraddr[1]}"
		log(str)
        @cs.write "220-\r\n\r\n Welcome to Volcano FTP server !\r\n\r\n220 Connected\r\n"
        Dir.chdir($path)

          while not (line = @cs.gets).nil?
          puts "[#{Process.pid}] Client sent : --#{line.chomp}--"
          log("[#{Process.pid}] Client sent : --#{line.chomp}--")
          ####
            command = "ftp_#{line.chomp.split(' ')[0].downcase}".to_sym
			send :"#{command}" , line.chomp.split(' ')[1]
          ####
        end
        puts "[#{Process.pid}] Killing connection from #{peeraddr[2]}:#{peeraddr[1]}"
        date = DateTime.now
        str = "[#{Process.pid}] " << date.to_s << " Killing connection from " << Process.pid.to_s
        log(str)
        @cs.close
        Kernel.exit!
      end
    end
  end

protected

  # Protected methods go here

end



# Main

begin
	ftp = VolcanoFtp.new($listen)
	ftp.run
rescue SystemExit, Interrupt
	puts "Caught CTRL+C, exiting"
rescue RuntimeError => e
	puts e
end
